home *** CD-ROM | disk | FTP | other *** search
- /*
- * Finite state machine routines.
- */
-
- #include "defs.h"
- #include <signal.h>
-
- #include "rtt.h" /* for RTT timing */
-
- #ifdef CLIENT
- int recv_ACK(), recv_DATA(), recv_RQERR();
- #endif
-
- #ifdef SERVER
- int recv_RRQ(), recv_WRQ(), recv_ACK(), recv_DATA();
- #endif
-
- int fsm_error(), fsm_invalid();
-
- /*
- * Finite state machine table.
- * This is just a 2-d array indexed by the last opcode sent and
- * the opcode just received. The result is the address of a
- * function to call to process the received opcode.
- */
-
- int (*fsm_ptr [ OP_MAX + 1 ] [ OP_MAX + 1 ] ) () = {
-
- #ifdef CLIENT
- fsm_invalid, /* [sent = 0] [recv = 0] */
- fsm_invalid, /* [sent = 0] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = 0] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = 0] [recv = OP_DATA] */
- fsm_invalid, /* [sent = 0] [recv = OP_ACK] */
- fsm_invalid, /* [sent = 0] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_RRQ] [recv = 0] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_WRQ] */
- recv_DATA, /* [sent = OP_RRQ] [recv = OP_DATA] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_ACK] */
- recv_RQERR, /* [sent = OP_RRQ] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_WRQ] [recv = 0] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_DATA] */
- recv_ACK, /* [sent = OP_WRQ] [recv = OP_ACK] */
- recv_RQERR, /* [sent = OP_WRQ] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_DATA] [recv = 0] */
- fsm_invalid, /* [sent = OP_DATA] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_DATA] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = OP_DATA] [recv = OP_DATA] */
- recv_ACK, /* [sent = OP_DATA] [recv = OP_ACK] */
- fsm_error, /* [sent = OP_DATA] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_ACK] [recv = 0] */
- fsm_invalid, /* [sent = OP_ACK] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_ACK] [recv = OP_WRQ] */
- recv_DATA, /* [sent = OP_ACK] [recv = OP_DATA] */
- fsm_invalid, /* [sent = OP_ACK] [recv = OP_ACK] */
- fsm_error, /* [sent = OP_ACK] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_ERROR] [recv = 0] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_DATA] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_ACK] */
- fsm_error /* [sent = OP_ERROR] [recv = OP_ERROR] */
- #endif /* CLIENT */
-
- #ifdef SERVER
- fsm_invalid, /* [sent = 0] [recv = 0] */
- recv_RRQ, /* [sent = 0] [recv = OP_RRQ] */
- recv_WRQ, /* [sent = 0] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = 0] [recv = OP_DATA] */
- fsm_invalid, /* [sent = 0] [recv = OP_ACK] */
- fsm_invalid, /* [sent = 0] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_RRQ] [recv = 0] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_DATA] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_ACK] */
- fsm_invalid, /* [sent = OP_RRQ] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_WRQ] [recv = 0] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_DATA] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_ACK] */
- fsm_invalid, /* [sent = OP_WRQ] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_DATA] [recv = 0] */
- fsm_invalid, /* [sent = OP_DATA] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_DATA] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = OP_DATA] [recv = OP_DATA] */
- recv_ACK, /* [sent = OP_DATA] [recv = OP_ACK] */
- fsm_error, /* [sent = OP_DATA] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_ACK] [recv = 0] */
- fsm_invalid, /* [sent = OP_ACK] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_ACK] [recv = OP_WRQ] */
- recv_DATA, /* [sent = OP_ACK] [recv = OP_DATA] */
- fsm_invalid, /* [sent = OP_ACK] [recv = OP_ACK] */
- fsm_error, /* [sent = OP_ACK] [recv = OP_ERROR] */
-
- fsm_invalid, /* [sent = OP_ERROR] [recv = 0] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_RRQ] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_WRQ] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_DATA] */
- fsm_invalid, /* [sent = OP_ERROR] [recv = OP_ACK] */
- fsm_error /* [sent = OP_ERROR] [recv = OP_ERROR] */
- #endif /* SERVER */
- };
-
- #ifdef DATAGRAM
- static struct rtt_struct rttinfo; /* used by the rtt_XXX() functions */
- static int rttfirst = 1;
-
- int tout_flag; /* set to 1 by SIGALRM handler */
- #endif /* DATAGRAM */
-
- /*
- * Main loop of finite state machine.
- *
- * For the client, we're called after either an RRQ or a WRQ has been
- * sent to the other side.
- *
- * For the server, we're called after either an RRQ or a WRQ has been
- * received from the other side. In this case, the argument will be a
- * 0 (since nothing has been sent) but the state table above handles
- * this.
- */
-
- int /* return 0 on normal termination, -1 on timeout */
- fsm_loop(opcode)
- int opcode; /* for client: RRQ or WRQ */
- /* for server: 0 */
- {
- register int nbytes;
-
- op_sent = opcode;
-
- #ifdef DATAGRAM
-
- if (rttfirst) {
- rtt_init(&rttinfo);
- rttfirst = 0;
- }
-
- rtt_newpack(&rttinfo); /* initialize for a new packet */
-
- for ( ; ; ) {
- int func_timeout(); /* our signal handler */
-
- signal(SIGALRM, func_timeout);
- tout_flag = 0;
- alarm(rtt_start(&rttinfo)); /* calc timeout & start timer */
-
- if ( (nbytes = net_recv(recvbuff, MAXBUFF)) < 0) {
- if (tout_flag) {
- /*
- * The receive timed out. See if we've tried
- * enough, and if so, return to caller.
- */
-
- if (rtt_timeout(&rttinfo) < 0) {
- #ifdef CLIENT
- printf("Transfer timed out\n");
- #endif
- return(-1);
- }
-
- if (traceflag)
- rtt_debug(&rttinfo);
- } else
- err_dump("net_recv error");
-
- /*
- * Retransmit the last packet.
- */
-
- net_send(sendbuff, sendlen);
- continue;
- }
-
- alarm(0); /* stop signal timer */
- tout_flag = 0;
- rtt_stop(&rttinfo); /* stop RTT timer, calc new values */
-
- if (traceflag)
- rtt_debug(&rttinfo);
-
- #else /* else we have a connection-oriented protocol (makes life easier) */
-
- for ( ; ; ) {
- if ( (nbytes = net_recv(recvbuff, MAXBUFF)) < 0)
- err_dump("net_recv error");
-
- #endif /* DATAGRAM */
-
- if (nbytes < 4)
- err_dump("receive length = %d bytes", nbytes);
-
- op_recv = ldshort(recvbuff);
-
- if (op_recv < OP_MIN || op_recv > OP_MAX)
- err_dump("invalid opcode received: %d", op_recv);
-
- /*
- * We call the appropriate function, passing the address
- * of the receive buffer and its length. These arguments
- * ignore the received-opcode, which we've already processed.
- *
- * We assume the called function will send a response to the
- * other side. It is the called function's responsibility to
- * set op_sent to the op-code that it sends to the other side.
- */
-
- if ((*fsm_ptr[op_sent][op_recv])(recvbuff + 2, nbytes - 2) < 0){
- /*
- * When the called function returns -1, this loop
- * is done. Turn off the signal handler for
- * timeouts and return to the caller.
- */
-
- signal(SIGALRM, SIG_DFL);
- return(0);
- }
- }
- }
-
- #ifdef DATAGRAM
-
- /*
- * Signal handler for timeouts.
- * Just set the flag that is looked at above when the net_recv()
- * returns an error (interrupted system call).
- */
-
- int
- func_timeout()
- {
- tout_flag = 1; /* set flag for function above */
- }
-
- #endif /* DATAGRAM */
-
- /*
- * Error packet received and we weren't expecting it.
- */
-
- /*ARGSUSED*/
- int
- fsm_error(ptr, nbytes)
- char *ptr;
- int nbytes;
- {
- err_dump("error received: op_sent = %d, op_recv = %d",
- op_sent, op_recv);
- }
-
- /*
- * Invalid state transition. Something is wrong.
- */
-
- /*ARGSUSED*/
- int
- fsm_invalid(ptr, nbytes)
- char *ptr;
- int nbytes;
- {
- err_dump("protocol botch: op_sent = %d, op_recv = %d",
- op_sent, op_recv);
- }
-